/*
 * ChannelPanel.java
 *
 * Created on 28 juin 2010, 21:34:47
 */
package darknet.application.chat.gui;

import darknet.application.chat.spec.Channel;
import darknet.application.chat.spec.ChannelObserver;
import darknet.application.chat.impl.net.message.BroadcastChannelMessage;
import darknet.application.chat.impl.net.message.BroadcastExitChannelMessage;
import darknet.application.chat.impl.net.message.BroadcastJoinChannelMessage;
import darknet.application.chat.impl.net.message.CloseChannelMessage;
import darknet.application.chat.impl.net.message.ExitChannelMessage;
import darknet.application.chat.impl.net.message.JoinChannelMessage;
import darknet.core.spec.net.Node;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingWorker;

/**
 * A panel for chat into a channel.
 *
 * @author Yoyo
 */
public class ChannelPanel extends JPanel implements ChannelObserver {

    /** Serial version */
    private static final long serialVersionUID = 1L;

    /** The channel */
    private Channel channel = null;

    /** Master panel */
    private ChatApplicationPanel master = null;

    /**
     * Creates new form ChannelPanel
     * @param channel
     * @param master
     */
    public ChannelPanel(Channel channel, ChatApplicationPanel master) {

        if (channel == null) {
            throw new IllegalArgumentException("channel is null");
        }
        this.channel = channel;

        if (master == null) {
            throw new IllegalArgumentException("master is invalid (null)");
        }
        this.master = master;

        // UI stuff
        initComponents();
        labelChannelName.setText(channel.getName());
        updateNodes();
    }

    /**
     * Update the node list
     */
    private void updateNodes() {

        // Get nodes
        List<String> nodes = new ArrayList<String>(10);
        for (Node node : channel.getNodes()) {
            nodes.add(node.getName());
        }

        // update UI
        listNodes.setListData(nodes.toArray());
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jLabel1 = new javax.swing.JLabel();
        labelChannelName = new javax.swing.JLabel();
        jScrollPane1 = new javax.swing.JScrollPane();
        listNodes = new javax.swing.JList();
        btnSend = new javax.swing.JButton();
        jScrollPane2 = new javax.swing.JScrollPane();
        editorpaneMessage = new javax.swing.JEditorPane();
        jScrollPane3 = new javax.swing.JScrollPane();
        textpaneMessages = new javax.swing.JTextArea();
        btnClose = new javax.swing.JButton();

        jLabel1.setText("Channel's name : ");

        labelChannelName.setText("[channel name here]");

        listNodes.setModel(new javax.swing.AbstractListModel() {
            String[] strings = { "Node's Name 1", "Node's Name 2", "Toto", "Tata", "Titi", "Tutu" };
            public int getSize() { return strings.length; }
            public Object getElementAt(int i) { return strings[i]; }
        });
        jScrollPane1.setViewportView(listNodes);

        btnSend.setText("Send");
        btnSend.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnSendActionPerformed(evt);
            }
        });

        jScrollPane2.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        editorpaneMessage.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyTyped(java.awt.event.KeyEvent evt) {
                editorpaneMessageKeyTyped(evt);
            }
        });
        jScrollPane2.setViewportView(editorpaneMessage);

        jScrollPane3.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        textpaneMessages.setColumns(20);
        textpaneMessages.setEditable(false);
        textpaneMessages.setRows(5);
        jScrollPane3.setViewportView(textpaneMessages);

        btnClose.setText("close");
        btnClose.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnCloseActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 572, Short.MAX_VALUE)
                        .addGap(18, 18, 18)
                        .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jLabel1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(labelChannelName, javax.swing.GroupLayout.DEFAULT_SIZE, 541, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(btnClose))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jScrollPane2)
                        .addGap(18, 18, 18)
                        .addComponent(btnSend, javax.swing.GroupLayout.PREFERRED_SIZE, 95, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1)
                    .addComponent(labelChannelName)
                    .addComponent(btnClose))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 346, Short.MAX_VALUE)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 346, Short.MAX_VALUE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                    .addComponent(btnSend, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 89, Short.MAX_VALUE))
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents

    private void btnSendActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSendActionPerformed

        sendTypedMessage();
        
    }//GEN-LAST:event_btnSendActionPerformed

    private void btnCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCloseActionPerformed

        btnClose.setEnabled(false);
        btnClose.setText("Closing...");

        try {

            channel.exit();
            master.newChannelExit(channel);

        } catch (IOException ex) {
            
            JOptionPane.showMessageDialog(
                    null, ex.getLocalizedMessage(),
                    "Exception", JOptionPane.WARNING_MESSAGE);
        }

        btnClose.setText("Close");
        btnClose.setEnabled(true);

    }//GEN-LAST:event_btnCloseActionPerformed

    private void editorpaneMessageKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_editorpaneMessageKeyTyped

        // Enter typed
        if (evt.getKeyChar() == '\n') {

            // ENTER with CTRL --> Add the enter to the editor
            if (evt.getModifiers() == 2) {
                editorpaneMessage.setText(editorpaneMessage.getText() + '\n');
            }
            // Enter without CTRL --> Send the message.
            else {
                sendTypedMessage();
            }
        }

    }//GEN-LAST:event_editorpaneMessageKeyTyped

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnClose;
    private javax.swing.JButton btnSend;
    private javax.swing.JEditorPane editorpaneMessage;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JLabel labelChannelName;
    private javax.swing.JList listNodes;
    private javax.swing.JTextArea textpaneMessages;
    // End of variables declaration//GEN-END:variables

    @Override
    public void newJoinChannelMessage(JoinChannelMessage event) {

        printJoinMessage(event.getFrom().getName());

        updateNodes();
    }

    @Override
    public void newBroadcastJoinChannelMessage(
            BroadcastJoinChannelMessage event) {

        printJoinMessage(event.getJoiner().getName());

        updateNodes();
    }

    @Override
    public void newBroadcastChannelMessage(BroadcastChannelMessage event) {

        printNodeMessage(event.getOriginalPoster().getName(), event.getText());
    }

     @Override
    public void newExitChannelMessage(ExitChannelMessage event) {

         printExitMessage(event.getFrom().getName());

         updateNodes();
    }

    @Override
    public void newBroadcastExitChannelMessage(BroadcastExitChannelMessage event) {

        printExitMessage(event.getExiter().getName());

        updateNodes();
    }

    @Override
    public void newCloseChannelMessage(CloseChannelMessage event) {

        printCloseMessage();
    }

    /**
     * Send a typed message.
     */
    private void sendTypedMessage() {

        new SwingWorker<Object, Object>() {

            @Override
            protected Object doInBackground() {

                btnSend.setEnabled(false);
                btnSend.setText("Sending...");

                String message = editorpaneMessage.getText();
                if (message.length() != 0) {

                    try {
                        channel.speak(message);
                    } catch (IOException ex) {
                        JOptionPane.showMessageDialog(
                                null, ex.getLocalizedMessage(),
                                "Exception", JOptionPane.WARNING_MESSAGE);
                    }
                }

                printMyMessage(message);
                editorpaneMessage.setText("");

                btnSend.setText("Send");
                btnSend.setEnabled(true);

                return null;
            }

        }.execute();
    }

    /**
     * Print a message on the text panel.
     *
     * @param message
     */
    private void printMessage(String message) {

        StringBuilder builder = new StringBuilder(textpaneMessages.getText());
        builder.append("\n");
        builder.append(message);
        builder.append("\n");

        textpaneMessages.setText(builder.toString());
    }

    /**
     * Print a response, as myself.
     *
     * @param message
     */
    private void printMyMessage(String message) {

        StringBuilder b = new StringBuilder();
        b.append("Me : ").append(message);
        printMessage(b.toString());
    }
    
    /**
     * Print a join message.
     *
     * @param name
     */
    private void printJoinMessage(String name) {

        StringBuilder b = new StringBuilder();
        b.append(name).append(" has joined");
        printMessage(b.toString());
    }

    /**
     * Print a node message.
     *
     * @param name
     * @param text
     */
    private void printNodeMessage(String name, String text) {

        StringBuilder b = new StringBuilder();
        b.append(name).append(" says :").append(text);
        printMessage(b.toString());
    }

    /**
     * Print an exit message.
     * 
     * @param name
     */
    private void printExitMessage(String name) {

        StringBuilder b = new StringBuilder();
        b.append(name).append(" has exit");
        printMessage(b.toString());
    }

    /**
     * Print a close channel message.
     */
    private void printCloseMessage() {

        StringBuilder b = new StringBuilder();
        b.append("The hoster has closed the channel");
        printMessage(b.toString());
    }
}
